package org.texteasy;

import java.util.HashSet;
import java.util.LinkedList;

import org.texteasy.helpers.ActiveThread;
import org.texteasy.helpers.TextEasyMessageServiceStates;
import org.texteasy.helpers.TextMessageToContact;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.util.Log;

public class TextEasyMessageService extends Service {

	public static final String MESSAGE_SENT_BROADCAST = "MessageSentBroadcast";
	
	public static final String MESSAGE_SENT_NUMBER = "MESSAGE_SENT_NUMBER";
	public static final String MESSAGE_ID="MESSAGE_ID";
	public static final String CONTACT_ID="CONTACT_ID";
	
	public static final String MESSAGE_EVENT="MESSAGE_EVENT";
	public static final int MESSAGE_ACCEPTED_EVENT = 1;
	public static final int MESSAGE_SENT_EVENT= 2;
	
	public static final int NOTIFY_ID = 541490;
	
	private TextEasyDBAdapter dbAdaptor;
	
	
	private static final String TAG = "TextEasyMessageService";
	
	private final MessageService.Stub binder = new MessageService.Stub(){
		
		@Override
		public void sendMessage(long[] contactIds, String textMessage)
				throws RemoteException {
			
			Log.e(TAG,"in Service send message");
			
			handler.newMessageEvent(contactIds, textMessage);
			
		}
		
		
		@Override
		public void cancelMessage(long messageId) throws RemoteException {
			
		}
	};
	
	private TextEasyMessageService getContext(){
		return this;
	}
	
	private TextEasyMessageWorkerThread handler = new TextEasyMessageWorkerThread();
	/*private Handler handler = new Handler(){
		
		private int messagesSent = 0;
		private int messagesTotal = 0;
		private boolean proccessRunning = false;
		
		@Override
		public void handleMessage(Message msg) {
			
			Bundle bundle = msg.getData();
			
			boolean enqueueProcessMessage = false;
			if(bundle.get(MESSAGE_COUNT) != null){
				
				messagesTotal += bundle.getInt(MESSAGE_COUNT);
				if(!proccessRunning){
					enqueueProcessMessage = true;
				}
			}else if(bundle.get(PROCESS_MESSAGE) != null){
				
				NotificationManager notificationManager = (NotificationManager)getSystemService(
						NOTIFICATION_SERVICE);
				
				if(messagesSent != messagesTotal){
					messagesSent++;
					
					Notification note = new Notification(R.drawable.notify_sending, null, System.currentTimeMillis());
			    	
			    	PendingIntent pendingIntent = PendingIntent.getActivity(getContext(), 0, new Intent(getContext(), MessagesInProgessList.class), 
						Notification.FLAG_ONGOING_EVENT);
			    	
			    	note.setLatestEventInfo(getContext(), "Text Easy", "Sending " + messagesSent + " of " + messagesTotal + " Messages", pendingIntent);
			    	note.number = messagesSent;
			    	notificationManager.notify(NOTIFY_ID, note);
					
			    	enqueueProcessMessage = true;
			    	
			    	Intent broadcastIntent = new Intent(MESSAGE_SENT_BROADCAST);
			    	broadcastIntent.putExtra(MESSAGE_SENT_NUMBER, messagesSent);
			    	sendBroadcast(broadcastIntent);
			    	
				}else{
					notificationManager.cancel(NOTIFY_ID);
					proccessRunning = false;
					messagesSent = 0;
					messagesTotal = 0;
				}
			}
			
			if(enqueueProcessMessage){
				Message message = handler.obtainMessage();
				Bundle data = new Bundle();
				data.putBoolean(PROCESS_MESSAGE, true);
				message.setData(data);
				handler.sendMessageAtTime(message, SystemClock.uptimeMillis() + 1000);
				proccessRunning = true;
			}
		}
		
	};*/
	
	@Override
	public void onCreate() {
		super.onCreate();
		
		Log.e(TAG, "create");
		
		this.dbAdaptor = new TextEasyDBAdapter(this);
        this.dbAdaptor.open();
        
        handler.start();
        handler.initializeEvent();
	}
	
	@Override
	public void onStart(Intent intent, int startId) {
		super.onStart(intent, startId);
		
		Log.e(TAG, "start");
	}
	
	@Override
	public void onRebind(Intent intent) {
		super.onRebind(intent);
		
		Log.e(TAG, "rebind");
	}
	
	@Override
	public boolean onUnbind(Intent intent) {
		Log.e(TAG, "unbind");
		return super.onUnbind(intent);
	}
	
	@Override
	public void onConfigurationChanged(Configuration newConfig) {
		super.onConfigurationChanged(newConfig);
		
		Log.e(TAG, "configurationChanged");
	}
	@Override
	public void onDestroy() {
		super.onDestroy();
		
		Log.e(TAG, "destroy");
		
		TextEasyMessageWorkerThread handler = this.handler;
		if(handler != null && 
			handler.isAlive()){
			
			handler.interrupt();
		}
		
		if(this.dbAdaptor.isOpen()){
			this.dbAdaptor.close();
		}
	}
	
	@Override
	public IBinder onBind(Intent intent) {
		return binder;
	}

	public final class TextEasyMessageWorkerThread extends ActiveThread{
		
		private TextEasyMessageServiceStates state;
		private LinkedList<Long> inProgressMessages = new LinkedList<Long>();
		private int totalNumberOfMessages = 0;
		private int numberOfMessagesSent = 0;
		
		
		private static final int EVENT_INITIALIZE=1; 
		private static final int EVENT_NEW_MESSAGE=2;
		private static final int EVENT_SEND_MESSAGE=3;
		
		public TextEasyMessageWorkerThread(){
			super();
		}
		
		@Override
		public void handleMessage(Message msg) {
			
			if(state == null){
				state = TextEasyMessageServiceStates.INITIAL_STATE;
			}
			
			boolean eventHandled = false;
			
			if(state == TextEasyMessageServiceStates.INITIAL_STATE){
				eventHandled = initialState(msg);
			}else if(state == TextEasyMessageServiceStates.WAITING_FOR_MESSAGES){
				eventHandled = waitingForMessages(msg);
			}else if(state == TextEasyMessageServiceStates.SENDING_MESSAGE){
				eventHandled = sendingMessage(msg);
			}
			
			if(!eventHandled){
				Log.i(TAG, "Unhandled event: " + msg.arg1 + " in state: " + state.getName());
			}
		}
		
		public void initializeEvent(){
			Message message = Message.obtain();
			message.arg1 = EVENT_INITIALIZE;
			addMessage(message);
		}
		
		public void newMessageEvent(long[] contactIds, String textMessage){
			Message message = Message.obtain();
			message.arg1 = EVENT_NEW_MESSAGE;
			message.obj = new Object[]{contactIds, textMessage};
			addMessage(message);
		}
		
		public void sendMessageEvent(){
			Message message = Message.obtain();
			message.arg1 = EVENT_SEND_MESSAGE;
			addMessage(message);
		}
		
		private boolean initialState(Message message){
			
			if(message.arg1 == EVENT_INITIALIZE){
				//check if any messages in queue to send
				HashSet<Long> inProcessMessages = dbAdaptor.getInProgressMessageIds();
				
				if(inProcessMessages.isEmpty()){
					transitionToState(TextEasyMessageServiceStates.WAITING_FOR_MESSAGES);
				}else{
					
					/*Resend the broadcast intent when starting to sent queued messages
					 * just in case the app was restarted and the UI never
					 * received it the first time
					 * Intent broadcastIntent = new Intent(MESSAGE_SENT_BROADCAST);
						broadcastIntent.putExtra(MESSAGE_EVENT, MESSAGE_ACCEPTED_EVENT);
				    	broadcastIntent.putExtra(MESSAGE_ID, messageId);
				    	sendBroadcast(broadcastIntent);
					 */
					
					throw new IllegalStateException("IMPLEMENT ME");
				}
				return true;
			}
			
			return false;
		}
		
		private boolean waitingForMessages(Message message){
			
			if(message.arg1 == EVENT_NEW_MESSAGE){
				
				Object[] data = (Object[])message.obj;
				long[] contactIds = (long[])data[0];
				String textMessage = (String)data[1];
				
				//long messageId = dbAdaptor.createNewMessage(textMessage, contactIds);
				long messageId = -1l;
				inProgressMessages.add(messageId);
				
				//now notify any listeners that the message is in progress and
				//give out the message id
				Intent broadcastIntent = new Intent(MESSAGE_SENT_BROADCAST);
				broadcastIntent.putExtra(MESSAGE_EVENT, MESSAGE_ACCEPTED_EVENT);
		    	broadcastIntent.putExtra(MESSAGE_ID, messageId);
		    	sendBroadcast(broadcastIntent);
				
		    	totalNumberOfMessages += contactIds.length;
		    	
				transitionToState(TextEasyMessageServiceStates.SENDING_MESSAGE);
				return true;
			}
			
			return false;
		}

		private boolean sendingMessage(Message message){
	
			if(message.arg1 == EVENT_SEND_MESSAGE){
				
				TextMessageToContact messageToContact = null;
				LinkedList<Long> inProgressMessages = this.inProgressMessages;
				while(true){
					
					if(inProgressMessages.isEmpty()){
						break;
					}
					long messageId = inProgressMessages.peek();
					
					messageToContact = dbAdaptor.getNextTextMessageToContact(messageId);
					
					if(messageToContact == null){
						inProgressMessages.poll();
						dbAdaptor.setTextMessageToSent(messageId);
					}else{
						break;
					}
				}
				
				NotificationManager notificationManager = (NotificationManager)getSystemService(
						NOTIFICATION_SERVICE);
				
				if(messageToContact != null){
					int numberOfMessagesSent = this.numberOfMessagesSent;
					
					PendingIntent pendingIntent = PendingIntent.getActivity(getContext(), 0, new Intent(getContext(), MessagesInProgessList.class), 
						Notification.FLAG_ONGOING_EVENT);
			    	
					Notification note = new Notification(R.drawable.notify_sending, null, System.currentTimeMillis());
			    	note.setLatestEventInfo(getContext(), "Text Easy", "Sending " + numberOfMessagesSent + " of " + totalNumberOfMessages + 
			    			" Messages", pendingIntent);
			    	note.number = (numberOfMessagesSent + 1);
			    	notificationManager.notify(NOTIFY_ID, note);
					
			    	this.numberOfMessagesSent++;
			    	
			    	Log.e(TAG, "updated " + dbAdaptor.setTextMessageToContactToSent(messageToContact.getId()) + " rows.");
			    	
			    	try{
			    		Thread.sleep(2000);
			    	}catch(Exception ex){
			    		
			    	}
			    	
			    	Intent broadcastIntent = new Intent(MESSAGE_SENT_BROADCAST);
					broadcastIntent.putExtra(MESSAGE_EVENT, MESSAGE_SENT_EVENT);
			    	broadcastIntent.putExtra(MESSAGE_ID, messageToContact.getMessageId());
			    	broadcastIntent.putExtra(CONTACT_ID, messageToContact.getContactId());
			    	sendBroadcast(broadcastIntent);
			    	
					sendMessageEvent();
				}else{
					
					//remove any notification
					notificationManager.cancel(NOTIFY_ID);
					transitionToState(TextEasyMessageServiceStates.WAITING_FOR_MESSAGES);
				}
				
				return true;
			}else if(message.arg1 == EVENT_NEW_MESSAGE){
				throw new IllegalStateException("IMPLEMENT ME");
			}
			
			return false;
		}
		
		private void transitionToState(TextEasyMessageServiceStates state){
			if(state == TextEasyMessageServiceStates.WAITING_FOR_MESSAGES){
				
				this.numberOfMessagesSent=0;
				this.totalNumberOfMessages=0;
				
			}else if(state == TextEasyMessageServiceStates.SENDING_MESSAGE){
				sendMessageEvent();
			}else{
				throw new IllegalStateException("IMPLEMENT ME");
			}
			
			this.state = state;
		}
		
	}
	
}
